package genedit.controller;

import genedit.gui.GMainFrame;
import genedit.model.Workspace;
import genedit.model.graph.GraphElement;
import genedit.model.graph.Link;
import genedit.view.graph.GraphWorkArea;

import java.awt.Dimension;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Iterator;

/**
 * Klasa enkapsulira ponašanje radne površine u stanju laso selekcije.
 * 
 * @author Nikola
 * @version 1.1 18/12/13
 */
public class LassoSelectionState extends State {

	/**
	 * Položaj od kog laso kreeć da se širi.
	 */
	private Point2D startingPoint;

	/**
	 * Pravougaonik koji označava granice laso-a.
	 */
	private Rectangle2D rect;

	/**
	 * Prilikom prevlačenja miša laso se širi, odnosno skuplja. Svi elementi
	 * obuhvaćeni lasom bivaju selektovani. Ukoliko je Shift pritisnuto laso se
	 * ponaša kao laso zumiranja, a ne selekcije. Zumiranje se, međutim,
	 * izvršava tek kada se otpusti miš. Ukoliko se drži Ctrl moguće je da
	 * ostanu u selekciji elementi koji su pre laso stanja bili u njoj, kao i
	 * elementi koji su samo u jednom periodu bili u okviru laso-a.
	 */
	public void mouseDragged(MouseEvent e) {

		Point2D position = e.getPoint();
		context.pointToUserSpace(position);

		if (!e.isControlDown() || e.isShiftDown()) {
			context.getView().getModel().removeAllSelectedElements();
		}

		double width = position.getX() - startingPoint.getX();
		double height = position.getY() - startingPoint.getY();
		if ((width < 0) && (height < 0)) {
			rect.setRect(position.getX(), position.getY(), Math.abs(width), Math.abs(height));
		} else if ((width < 0) && (height >= 0)) {
			rect.setRect(position.getX(), startingPoint.getY(), Math.abs(width), Math.abs(height));
		} else if ((width > 0) && (height < 0)) {
			rect.setRect(startingPoint.getX(), position.getY(), Math.abs(width), Math.abs(height));
		} else {
			rect.setRect(startingPoint.getX(), startingPoint.getY(), Math.abs(width),
					Math.abs(height));
		}

		if (!e.isShiftDown()) {
			Iterator<GraphElement> it = context.getView().getModel().getIteratorElements();
			while (it.hasNext()) {
				GraphElement element = it.next();
				if (!(element instanceof genedit.model.graph.Link)) {
					Rectangle2D temp = new Rectangle2D.Double();
					Rectangle2D.union(rect, new Rectangle2D.Double(element.getPosition().getX(),
							element.getPosition().getY(), element.getSize().getWidth(), element
									.getSize().getHeight()), temp);
					if (rect.contains(temp))
					/*
					 * if
					 * (rect.intersects(element.getElement().getPosition().getX
					 * (), element.getElement().getPosition().getY(), element
					 * .getElement().getSize().getWidth(), element
					 * .getElement().getSize().getHeight()))
					 */{
						if (!context.getView().getModel().getSelectedElements().contains(element))
							context.getView().getModel().addSelectedElements(element);
					}
				} else {
					// Treba gledati za veze kako cemo
					Link link = (Link) element;
					if (rect.contains(genedit.view.graph.LinkPainter.findRectangle(link))) {
						if (!context.getView().getModel().getSelectedElements().contains(element))
							context.getView().getModel().addSelectedElements(element);
					}
				}
			}
		}

		context.setSelectionRectangle(rect);

		context.repaint();

	}

	/**
	 * Ukoliko je Shift bio spušten prilikom otpuštanja radna površina se zumira
	 * na nivo lasoa (poštujući ograničenja maksimalne i minimalne vrednosti
	 * faktora skaliranja). Nezavisno od stanja, nakon otpuštanja kontroler
	 * prelazi u stanje selekcije.
	 */
	public void mouseReleased(MouseEvent e) {
		if (e.isShiftDown()) {
			double Xmin = rect.getMinX();
			double Xmax = rect.getMaxX();
			double Ymin = rect.getMinY();
			double Ymax = rect.getMaxY();

			Dimension windowSize = GMainFrame.getInstance().getGraphDocumentViewDimension(
					Workspace.getInstance().getActiveDocument().getModel());

			double scaleFactor = 1;
			double neededHeight = Math.abs(Ymax - Ymin);
			double neededWidth = Math.abs(Xmax - Xmin);

			if (neededHeight - windowSize.getHeight() > neededWidth - windowSize.getWidth()) {
				scaleFactor = windowSize.getHeight() / neededHeight;

			} else {
				scaleFactor = windowSize.getWidth() / neededWidth;
			}

			GraphWorkArea workArea = ((GraphWorkArea) Workspace.getInstance().getActiveDocument()
					.getWorkArea());
			workArea.setScaling(scaleFactor);
			workArea.setTranslateX(-Xmin);
			workArea.setTranslateY(-Ymin);
			workArea.setupTransformation();
		}
		context.setSelectionRectangle(new Rectangle2D.Double(0, 0, 0, 0));
		context.repaint();
		context.getController().setCurrentState(new SelectionState(context));
	}

	public void keyPressed(KeyEvent e) {
		// TODO: implement
	}

	public LassoSelectionState(GraphWorkArea context, Point2D startingPoint) {
		super(context);
		this.startingPoint = startingPoint;
		this.rect = new Rectangle2D.Double();
	}
}